﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Collections.Specialized;

using System.Reflection;
using System.Web;
using System.IO;
using Microsoft.VisualBasic;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using Commons;
using System.Data;

namespace lxwmvc
{
    /// <summary>
    /// 功能:系统初始化菜单
    /// [11-03-08 15:39  周二 lxw]<para />
    /// </summary>
    public class applicationhelper
    {
        public static Dictionary<string, menuAttribute> hasMenu = new Dictionary<string, menuAttribute>();
        public static Dictionary<string, powerAttribute> hasPower = new Dictionary<string, powerAttribute>();

        /// <summary>
        /// 依赖的ID
        /// </summary>
        public static Dictionary<string, string[]> hasViews = new Dictionary<string, string[]>();
        /// <summary>
        /// 动态页面
        /// </summary>
        public static Dictionary<string, string> syspages = new Dictionary<string, string>();

        /// <summary>
        /// 城市页面
        /// </summary>
        public static Dictionary<string, string> citypage = new Dictionary<string, string>();

        /// <summary>
        /// 得到系统表结构
        /// </summary>
        public static DataTable systableinfo = null;
        /// <summary>
        /// 表的主键值
        /// </summary>
        public static Dictionary<string, string> pks = new Dictionary<string, string>();

        internal static Type lxwmvcdll = null;


        /// <summary>
        /// 初始化表结构
        /// </summary>
        public static void initsystableinfo()
        {
            
            var sql = @"
SELECT 
(case when a.colorder=1 then d.name else '' end) N'tablename',
a.name N'column',
(case when COLUMNPROPERTY( a.id,a.name,'IsIdentity')=1 then '1'else '0' end) N'pk',
b.name N'type',
a.length N'len',
(case when a.isnullable=1 then '1'else '0' end) N'null'
FROM  syscolumns  a left join systypes b 
on  a.xtype=b.xusertype
inner join sysobjects d 
on a.id=d.id  and  d.xtype='U' and  d.name<>'dtproperties'
left join syscomments e
on a.cdefault=e.id
order by object_name(a.id),a.colorder            
";
            //加载外部页面
            try
            {
                systableinfo = sqlhelper.out_getds(sql).Tables[0];
                string tablename = "";
                for (int i = 0; i < systableinfo.Rows.Count; i++)
                {
                    if (systableinfo.Rows[i]["tablename"].tostr().Length > 0)
                    {
                        tablename = systableinfo.Rows[i]["tablename"].tostr();
                    }
                    else
                    {
                        //赋值，把没有信息的补全
                        systableinfo.Rows[i]["tablename"] = tablename;
                    }

                    if (systableinfo.Rows[i]["pk"].tostr() == "1")
                    {
                        //得到表的递增列
                        pks[tablename.ToLower()] = systableinfo.Rows[i]["column"].tostr();
                    }
                }
            }
            catch { }

        }

        /// <summary>
        /// 初始化系统页面
        /// </summary>
        public static void initsyspages()
        {
            //加载外部页面
            try
            {
                var sql = "select http,syspagesid from syspages";
                DataSet ds = sqlhelper.out_getds(sql);
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    //存储到队列中，以后直接读取
                    syspages[dr["http"].tostr().ToLower()] = dr["syspagesid"].tostr();
                }
            }
            catch { }
        }

        /// <summary>
        /// 初始化系统页面
        /// </summary>
        public static void initcitypages()
        {
            //加载外部页面
            try
            {
                var sql = "select jiancheng from city";
                DataSet ds = sqlhelper.out_getds(sql);
                foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    //存储到队列中，以后直接读取
                    citypage[dr["jiancheng"].tostr().ToLower()] = dr["jiancheng"].tostr();
                }
            }
            catch { }
        }

        /// <summary>
        /// 功能:初始化菜单和权限
        /// [11-03-08 15:47  周二 lxw]<para />
        /// </summary>
        /// <param name="container"></param>
        public static void initmenupower(Type pagebasetype)
        {
            //设置程序集
            lxwmvcdll = pagebasetype;

            string strConfig = "lxwmvc.config";
            string strPath = HttpContext.Current.Server.MapPath("/");//寻找root目录
            try { Directory.CreateDirectory(Path.Combine(strPath, strConfig)); }
            catch { }

            //初始化表结构
            initsystableinfo();

            //初始化系统页面
            initsyspages();

            //初始化系统页面
            initcitypages();
            

            //先序列化
            string strMenuPath = "/" + strConfig + "/lxwmenu.dll";
            string strPowerPath = "/" + strConfig + "/lxwpower.dll";

            //先每次都能打开
            if (File.Exists(HttpContext.Current.Server.MapPath(strMenuPath))
                 && File.Exists(HttpContext.Current.Server.MapPath(strPowerPath))
                 )
            {
                try
                {
                    readbindll(strMenuPath, hasMenu, typeof(menuAttribute));
                    readbindll(strPowerPath, hasPower, typeof(powerAttribute));
                }
                catch {
                    dataloger.writelog("读取" + strMenuPath+"出现错误,请设置文件夹everyone可读写。");
                }
            }
            else  
            {
                //判断重复名称Controller
                //[11-03-10 10:42 lxw]
                var types = pagebasetype.Assembly.GetTypes();

                foreach (var type in types)
                {
                    Type classType = type;
                    string strBaseAssemblyName = classType.FullName.ToLower();
                    if (!strBaseAssemblyName.EndsWith("controller")) continue;

                    MethodInfo[] methods = classType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);

                    foreach (MethodInfo method in methods)
                    {
                        object[] attributesmenu = method.GetCustomAttributes(typeof(menuAttribute), true);
                        object[] attributespower = method.GetCustomAttributes(typeof(powerAttribute), true);
                        object[] attributesdepend = method.GetCustomAttributes(typeof(yilaiAttribute), true);

                        //生成菜单的一些基本信息
                        string strcontroller = classType.Name.ToLower();
                        strcontroller = strcontroller.Replace("controller", "");

                        if (attributesmenu != null && attributesmenu.Length == 1)
                        {
                            menuAttribute _atmenu = attributesmenu[0] as menuAttribute;                            
                            //菜单编号
                            _atmenu.menuname = "m@" + strcontroller.ToUpper() + "@" + method.Name.ToUpper();

                            _atmenu.actionpath = "/" + strcontroller + "/" + method.Name.ToLower() + "";

                            //不可能再出现重复
                            //[11-03-10 13:15 lxw]
                            if (hasMenu.ContainsKey(_atmenu.menuname.ToLower()))
                                throw new Exception(
                                    string.Format("存在相同的菜单ID:{0},两个名称是:{1}/{2}",
                                    _atmenu.menuname,
                                    (hasMenu[_atmenu.menuname] as menuAttribute).title,
                                    _atmenu.title
                                    ));

                            //_atmenu.MenuImage = "/content/" + strAssemblyName + "/images/menu/" + _atmenu.MenuImage;
                            hasMenu[_atmenu.menuname.ToLower()] = _atmenu;
                        }

                        if (attributespower != null && attributespower.Length == 1)
                        {
                            powerAttribute _atpower = attributespower[0] as powerAttribute;
                            //权限编号
                            _atpower.powername = "P@" + strcontroller.ToUpper() + "@" + method.Name.ToUpper();

                            _atpower.checkvalidate();

                            //不可能再出现重复
                            //[11-03-10 13:15 lxw]
                            if (hasPower.ContainsKey(_atpower.powername.ToLower()))
                                throw new Exception(
                                    string.Format("存在相同的权限ID:{0},两个名称是:{1}/{2}",
                                    _atpower.powername,
                                    (hasPower[_atpower.powername] as powerAttribute).title,
                                    _atpower.title
                                    ));


                            hasPower[_atpower.powername.ToLower()] = _atpower;
                        }

                        if (attributesdepend != null && attributesdepend.Length == 1)
                        {
                            yilaiAttribute _atdepend = attributesdepend[0] as yilaiAttribute;
                            _atdepend.checkvalidate();//校验
                        }
                    }
                }

                //遍历views
                DirectoryInfo di = new DirectoryInfo(strPath + "/views");
                foreach (var d in di.GetDirectories())
                {
                    string dname = d.Name;
                    //布局的排除在外
                    if (dname.ToLower() == "layout") continue;
                    FileInfo[] fis = d.GetFiles("*.htm");
                    List<string[]> lst = new List<string[]>();
                    foreach (var f in fis)
                    {
                        string fname = Path.GetFileNameWithoutExtension(f.FullName);
                        string menuname = ("M@" + dname + "@" + fname).ToLower();
                        string powername = ("p@" + dname + "@" + fname).ToLower();
                        //证明已经存在action里面的内容了
                        if (hasMenu.ContainsKey(menuname) || hasPower.ContainsKey(powername)) continue;

                        StreamReader sr = new StreamReader(f.FullName, Encoding.Default);
                        string header = sr.ReadLine();
                        sr.Close();

                        //存在才执行
                        while (true && header!=null && header.Replace(" ", "").Length > 0)
                        {
                            if (header.IndexOf("##[menu(\"") != -1)
                            {
                                string name = header.Substring(9, header.LastIndexOf("\"") - 9);
                                lst.Add(new string[] { "menu",dname, fname, name,"" });
                                break;
                            }
                            if (header.IndexOf("##[power(\"") != -1)
                            {
                                string name = header.Substring(10, header.LastIndexOf("\"") - 10);
                                name = name.Replace(" ", "");
                                lst.Add(new string[] { "power", dname, fname, Regex.Split(name, "\",\"")[0], Regex.Split(name, "\",\"")[1] });
                                break;
                            }
                            if (header.IndexOf("##[yilai(\"") != -1)
                            {
                                string name = header.Substring(9, header.LastIndexOf("\")") - 9);
                                //foreach (var s in name.Split(','))
                                //{
                                //    lst.Add(new string[] { "yilai", dname, fname, s, "" });
                                //}
                                lst.Add(new string[] { "yilai", dname, fname, name, "" });
                                
                                break;
                            }
                            break;
                        }
                    }


                    //============================================>
                    //循环
                    foreach (var l in lst)
                    {
                        string path = l[1].ToUpper() + "/" + l[2].ToUpper();
                        //访问这个view的时候，需要检查权限
                        hasViews[path] = l;

                        if (l[0] == "menu")
                        {
                            menuAttribute _atmenu = new menuAttribute(l[3]);
                            //菜单编号
                            _atmenu.menuname = "M@" + l[1].ToUpper() + "@" + l[2].ToUpper();

                            //这个设置比较变态
                            _atmenu.actionpath = "/table/" + l[1] + "/" + l[1] + "id/" + l[2].ToLower() + "";
                            //不可能再出现重复
                            //[11-03-10 13:15 lxw]
                            if (hasMenu.ContainsKey(_atmenu.menuname.ToLower()))
                                throw new Exception(
                                    string.Format("存在相同的菜单ID:{0},两个名称是:{1}/{2}",
                                    _atmenu.menuname,
                                    (hasMenu[_atmenu.menuname] as menuAttribute).title,
                                    _atmenu.title
                                    ));

                            //_atmenu.MenuImage = "/content/" + strAssemblyName + "/images/menu/" + _atmenu.MenuImage;
                            hasMenu[_atmenu.menuname.ToLower()] = _atmenu;
                            continue;
                        }
                        if (l[0] == "power")
                        {
                            powerAttribute _atpower = new powerAttribute(l[3], l[4]);
                            //权限编号
                            _atpower.powername = "P@" + l[1].ToUpper() + "@" + l[2].ToUpper();
                            _atpower.checkvalidate();

                            //不可能再出现重复
                            //[11-03-10 13:15 lxw]
                            if (hasPower.ContainsKey(_atpower.powername.ToLower()))
                                throw new Exception(
                                    string.Format("存在相同的权限ID:{0},两个名称是:{1}/{2}",
                                    _atpower.powername,
                                    (hasPower[_atpower.powername] as powerAttribute).title,
                                    _atpower.title
                                    ));


                            hasPower[_atpower.powername.ToLower()] = _atpower;
                            continue;
                        }
                        if (l[0] == "yilai")
                        {
                            //string path = l[1].ToUpper() + "/" + l[2].ToUpper();
                            //hasViewYiLai[path] = l[3];
                        }
                    }

                }
                

                createbindll(strMenuPath, hasMenu, typeof(menuAttribute));
                createbindll(strPowerPath, hasPower, typeof(powerAttribute));                
            }

            try
            {
                string sql = "select * from caidan where leixing='0' ";
                DataTable dtmenu = sqlhelper.out_getds(sql).Tables[0];//系统数据库已存在的所有系统菜单

                string menus = "";

                sql = "insert into caidan(menuname,actionpath,title,sfxianshi,leixing,shangji,jibie,paixu) values('{0}','{1}','{2}','{3}','{4}','{5}','{6}',{7})";
                foreach (menuAttribute menu in applicationhelper.hasMenu.Values)
                {
                    menus += menus == "" ? "'" + menu.menuname + "'" : ",'" + menu.menuname + "'";
                    if (dtmenu.Select(" menuname='" + menu.menuname + "'").Length == 0)//系统中不存在  则插入
                    {
                        LxwData has = new LxwData();
                        has["menuname"] = menu.menuname;
                        has["actionpath"] = menu.actionpath;
                        has["title"] = menu.title;
                        has["paixu"] = 0;//排序默认为0
                        has["leixing"] = "0";//系统菜单
                        has["jibie"] = 1;
                        has["shangji"] = "";
                        has["sfxianshi"] = "1";

                        sqlhelper.out_exec(string.Format(sql,//插入
                            has["menuname"],
                            has["actionpath"],
                            has["title"],
                            has["sfxianshi"],
                            has["leixing"],
                            has["shangji"],
                            has["jibie"],
                            has["paixu"]));
                    }
                }

                //删除 被删除的菜单
                sql = "delete from caidan where leixing='0' and menuname not in(" + menus + ") ";
                sqlhelper.out_exec(sql);
            }
            catch
            {

            }
        }

        /// <summary>
        /// 功能:把has表生成缓存文件
        /// [11-03-08 15:47  周二 lxw]<para />
        /// </summary>
        /// <param name="strPathName">路径</param>
        /// <param name="has">哈希表</param>
        /// <param name="type">类型</param>
        static void createbindll(string strPathName, IDictionary has, Type type)
        {
            ArrayList arr = new ArrayList();
            foreach (Attribute item in has.Values)
                arr.Add(item);

            //序列化存储到BIN目录。
            FileStream fs = File.Open(HttpContext.Current.Server.MapPath(strPathName), FileMode.OpenOrCreate);
            Type[] ext = new Type[1];
            ext[0] = type;

            XmlSerializer xs = new XmlSerializer(typeof(ArrayList), ext);
            XmlTextWriter tw = new XmlTextWriter(fs, Encoding.Default);
            xs.Serialize(tw, arr);

            fs.Flush();
            fs.Close();
        }

        /// <summary>
        /// 功能:从文件中读取出来到哈希表
        /// [11-03-08 15:48  周二 lxw]<para />
        /// </summary>
        /// <param name="strPathName">文件路径</param>
        /// <param name="has">哈希表</param>
        /// <param name="type">类型</param>
        static void readbindll(string strPathName, IDictionary has, Type type)
        {
            FileStream fs = File.Open(HttpContext.Current.Server.MapPath(strPathName), FileMode.Open);
            Type[] ext = new Type[1];
            ext[0] = type;

            XmlSerializer xs = new XmlSerializer(typeof(ArrayList), ext);
            StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);
            ArrayList arr = (ArrayList)xs.Deserialize(sr);
            if (typeof(menuAttribute) == type)
                foreach (menuAttribute item in arr)
                    has[item.menuname.ToLower()] = item;//注意都要小写
            else
                foreach (powerAttribute item in arr)
                    has[item.powername.ToLower()] = item;//注意都要小写
        }


        /// <summary>
        /// 设置权限
        /// </summary>
        /// <param name="juseid">对应数据库 角色id</param>
        public static void setpowerstring(int jueseid)
        {
            cookieshelper.setcookie("jueseid", jueseid.tostr());

            //系统管理员，可以看见所有的权限
            if (jueseid == 1)
            {
                string powerstring = "";
                DataTable drs = sqlhelper.out_getds("select * from caidan ").Tables[0];// supermodel.create("caidan").select("*").more();

                foreach (DataRow menu in drs.Rows)
                {
                    powerstring += powerstring != "" ? ",'" + menu["menuname"] + "'" : "'" + menu["menuname"] + "'";
                }
                foreach (powerAttribute power in applicationhelper.hasPower.Values)
                {
                    powerstring += powerstring != "" ? ",'" + power.powername + "'" : "'" + power.powername + "'";
                }

                globalhelper.powerstring = powerstring.Replace("'", "");
            }
            else//普通用户，必须根据权限访问。
            {
                string sql = "select * from juese where jueseid=" + jueseid;
                DataTable dtjuese = sqlhelper.executedataset(sql).Tables[0];
                if (dtjuese.Rows.Count > 0)
                {
                    string str = "";
                    if (dtjuese.Rows[0]["menus"].tostr() != "")
                    {
                        str = "'" + dtjuese.Rows[0]["menus"].tostr().TrimStart(',').TrimEnd(',').Replace(",", "','") + "'";
                    }
                    if(dtjuese.Rows[0]["powers"].tostr()!="")
                    {
                        if(str!="")
                        {
                            str+=",";
                        }
                        str+= "'" + dtjuese.Rows[0]["powers"].tostr().TrimStart(',').TrimEnd(',').Replace(",", "','") + "'";
                    }

                    //设置权限
                    globalhelper.powerstring = str.ToLower().Replace("'","");
                }
            }
        }
    }
}
